from abc import ABCMeta, abstractmethod
import clang.cindex as ci
import igraph
import logging
import types

__author__ = 'totem3006'

NDW_INFO  = logging.INFO
NDW_DEBUG = logging.DEBUG
NDW_ERROR = logging.ERROR

def get_logger(it = None):
    if it is None:
        import inspect
        name = inspect.currentframe().f_back.f_code.co_name
    else:
        name = it.__name__

   # extra = {"lineno": inspect.currentframe().f_back.f_lineno, }
    logger = logging.getLogger(name)
    return logger

def logable(cls):
    logger = get_logger(cls)
    def __log(self, treshold, fmt, *args, **kwargs):
        self.__logger.log(treshold, fmt, *args, **kwargs)

    setattr(cls, "log", __log)
    setattr(cls, "__logger", logger)
    return cls


def trace_method(func):
    def wrapped(self, *args, **kwargs):
        self.log(NDW_DEBUG, "Entering: [%s] with parameters %s" % (func.__name__, args))
        res = func(self, *args, **kwargs)
        if res is None:
            returns = ""
        else:
            returns = " returns [%s]" % res
        self.log(NDW_DEBUG, "Leave: [%s]%s", func.__name__, returns)

        return res
    return wrapped


def trace_function(func):
    logger = get_logger(func)
    def wrapped(*args, **kwargs):
        logger.log(NDW_DEBUG, "Entering: [%s] with parameters %s, %s" % (func.__name__, args, kwargs))
        res = func(*args, **kwargs)
        if res is None:
            returns = ""
        else:
            returns = " returns [%s]" % res

        logger.log(NDW_DEBUG, "Leave: [%s]%s", func.__name__, returns)

        return res

    return wrapped


def walk_ast_tree(node, parent, callback, **kwargs):
    """
    :param node:
    :param parent:
    :param callback: function that have 2 arg: (node, parent). Return 0 if success
    :return:
    """
    assert(type(node) is ci.Cursor)
    assert(type(parent) is ci.Cursor or parent in None)
    assert(isinstance(callback, types.FunctionType))

    if node != ci.conf.lib.clang_getNullCursor():
        rc = callback(node, parent, **kwargs)

        if rc == 0:
            for ch in node.get_children():
                walk_ast_tree(ch, node, callback, **kwargs)

